
from urllib import urlencode
from urllib2 import urlopen, Request, HTTPError
from xml.dom.minidom import parseString

import logging
logging.basicConfig(level=logging.DEBUG)

def debug(txt):
    return logging.debug(txt)


class LoginError(Exception):
    """Bad Login"""


class PostingError(Exception):
    """Unable to POST"""


class BlogFetchClient(object):

    def __init__(self, auth, feed_url):
        self._blog_auth = auth
        self._feed_url = feed_url
        self.reset()

    def reset(self):
        debug('Fetching feed for %s' % self._feed_url)
        self._feed_data = self._fetch_feed_data()
        self._xml_doc = self._parse_feed_data()
        self._entries = self._get_entries()

    def _fetch_feed_data(self):
        return urlopen(self._feed_url).read()

    def _parse_feed_data(self):
        return parseString(self._feed_data).documentElement

    def _get_entries(self):
        return [BlogItemEntry(self._blog_auth, node) for node in
                self._xml_doc.getElementsByTagName('entry')]

    def get_blog_items(self):
        return self._entries


class BlogItemEntry(object):

    def __init__(self, auth, node):
        self._node = node
        self._blog_auth = auth
        self.reset()

    def reset(self):
        self._raw_id = self._get_node_text('id')
        self.title = self._get_node_text('title')
        self.content = self._get_node_text('content')
        debug('Blog Item Entry parsed for "%s"' % self.title)
        self.edit_uri = self._get_edit_uri()

    def _get_text(self, node):
        return node.childNodes[0].data

    def _get_node(self, name):
        return self._node.getElementsByTagName(name)[0]

    def _get_node_text(self, name):
        return self._get_text(self._get_node(name))

    def _get_edit_uri(self):
        for node in self._node.getElementsByTagName('link'):
            if node.getAttribute('rel') == 'edit':
                return node.getAttribute('href')

    def edit(self, title, content):
        print [content]
        entry = self._create_edit_entry(title, content)
        req = self._create_edit_request(entry)
        if self._edit_entry(req):
            return True
        else:
            raise Exception('Unable to POST')

    def _create_edit_entry(self, title, content):
        return ENTRY_TEMPLATE % dict(
            title=title,
            content=content,
            author_name=self._blog_auth.get_email(),
            author_email=self._blog_auth.get_email()
        )

    def _create_edit_request(self, entry):
        req = Request(
            self.edit_uri,
            headers = {
                'content-type': 'application/atom+xml',
                'X-HTTP-Method-Override': 'PUT'
            },
            data=entry,
        )
        self._blog_auth.add_request_header(req)
        return req

    def _edit_entry(self, req):
        page = urlopen(req).read()
        return True




class BlogAuthClient(object):

    """
    For logging in to the GData Blogger API
   
    http://code.google.com/apis/accounts/AuthForInstalledApps.html
    """

    def __init__(self, email, password):
        self._email = email
        self._password = password
        debug ('logging in for email: %s' % self._email)
        self._auth_token = self._get_auth_token()
        debug ('logged in for email: %s' % self._email)

    def add_request_header(self, req):
        req.add_header('Authorization', self._get_auth_header_value())

    def get_email(self):
        return self._email
    
    def _get_auth_header_value(self):
        return 'GoogleLogin auth=%s' % self._auth_token

    def _get_auth_token(self):
        page = urlopen(LOGIN_URL, data=self._create_login_data()).read()
        auth = None
        error = None
        for line in page.splitlines():
            if line.startswith('Auth'):
                auth = line.strip()
            elif line.startswith('Error'):
                error = line.strip()
        if error:
            raise LoginError(error)
        return auth.split('=')[-1]
        
        
    def _create_login_data(self):
        return urlencode(
            {
            'accountType': 'HOSTED_OR_GOOGLE',
            'Email': self._email,
            'Passwd': self._password,
            'service':'blogger',
            'source': 'PIDAProject-pybloggerlib-1',
            }
        )


class BlogPostClient(object):

    def __init__(self, blogauth, posturl):
        self._post_url = posturl
        self._blog_auth = blogauth

    def post(self, title, content, author_name=None, author_email=None):
        entry = self._create_post_entry(
            title,
            content,
            author_name,
            author_email
        )
        req = self._create_post_request(entry)
        if self._post_entry(req):
            return True
        else:
            raise Exception('Unable to POST')

    def _create_post_entry(self, title, content, author_name=None, author_email=None):
        return ENTRY_TEMPLATE % dict(
            title=title,
            content=content,
            author_name=author_name or self._blog_auth.get_email(),
            author_email=author_email or self._blog_auth.get_email()
        )

    def _create_post_request(self, entry):
        req = Request(
            self._post_url,
            headers = {
                'content-type': 'application/atom+xml',
            },
            data=entry,
        )
        self._blog_auth.add_request_header(req)
        return req

    def _post_entry(self, req):
        try:
            page = urlopen(req).read()
            raise PostingError(page)
        except HTTPError, e:
            if e.code == 201:
                return True
            else:
                raise PostingError(e)


class BlogEntry(object):

    def __init__(self, blogauth, blogentrynode):
        self._blog_auth = blogauth
        self._node = blogentrynode
        self.reset()

    def reset(self):
        self._raw_id = self._get_node_text('id')
        self._id = self._raw_id.split('-')[-1]
        self.title = self._get_node_text('title')
        debug('Parsing Blog Entry data for %s' % self.title)
        self.summary = self._get_node_text('summary')
        self._get_link_nodes()
        self._post_client = BlogPostClient(self._blog_auth, self.get_post_url())
        self._feed_client = BlogFetchClient(self._blog_auth, self.get_feed_url())

    def _get_text(self, node):
        return node.childNodes[0].data

    def _get_node(self, name):
        return self._node.getElementsByTagName(name)[0]

    def _get_node_text(self, name):
        return self._get_text(self._get_node(name))

    def _get_id_node(self):
        print self._node.getElementsByTagName('id')[0]

    def get_feed_url(self):
        return self._feed_url

    def get_post_url(self):
        return self._post_url

    def _get_link_nodes(self):
        for node in self._node.getElementsByTagName('link'):
            rel = node.getAttribute('rel')
            href = node.getAttribute('href')
            if rel == 'http://schemas.google.com/g/2005#feed':
                self._feed_url = href
            elif rel == 'http://schemas.google.com/g/2005#post':
                self._post_url = href
            elif rel == 'alternative':
                self._blog_url = href
            elif rel == 'self':
                self._self_url = href
            elif rel == 'edit':
                self._edit_url = href

    def get_blog_items(self):
        return self._feed_client.get_blog_items()

    def post(self, title, content):
        self._post_client.post(title, content)



class BlogListClient(object):

    def __init__(self, blogauth):
        self._blog_auth = blogauth
        self.reset()

    def reset(self):
        debug('Fetching blog list for email: %s' % self._blog_auth.get_email())
        self._feed_data = self._fetch_blogs_feed()
        self._xml_doc = self._parse_feed_data()
        self._entry_nodes = self._xml_doc.documentElement.getElementsByTagName('entry')
        self._entries = [BlogEntry(self._blog_auth, n) for n in self._entry_nodes]

    def _parse_feed_data(self):
        return parseString(self._feed_data)

    def _fetch_blogs_feed(self):
        return urlopen(self._create_list_request()).read()

    def _create_list_request(self):
        req = Request(LIST_URL)
        self._blog_auth.add_request_header(req)
        return req

    def get_blogs(self):
        return self._entries


class BlogClient(object):
    
    def __init__(self):
        self._auth_client = None
        self._list_client = None

    def connect(self, email, password):
        try:
            self._auth_client = BlogAuthClient(email, password)
            return True
        except Exception, e:
            raise

    def load(self):
        self._list_client = BlogListClient(self._auth_client)

    def get_blogs(self):
        if self._list_client:
            return self._list_client.get_blogs()
        else:
            return []





LIST_URL = "http://www.blogger.com/feeds/default/blogs"

FEED_URL_TEMPLATE = 'http://%s.blogspot.com/feeds/posts/default'

LOGIN_URL = 'https://www.google.com/accounts/ClientLogin'

POST_URL_TEMPLATE = 'http://www.blogger.com/feeds/%s/posts/default'

ENTRY_TEMPLATE = """<entry xmlns='http://www.w3.org/2005/Atom'>
<title type='text'>%(title)s</title>
<content type='xhtml'>%(content)s</content>
  <author>
    <name>%(author_name)s</name>
    <email>%(author_email)s</email>
  </author>
</entry>"""





